import tester.*;

/**
 * @author Adam Blackwell & Ryan Cassidy 
 */
// All the examples and tests for all things Account like.
public class Examples {

  // The default constructor.
  public Examples(){}

  // Initialize the checking accounts.
  IAccount check1 = new Checking(0001, 0, "First Checking Account", 0);
  IAccount check2 = new Checking(0002, 100, "Second Checking Account", 50);
  IAccount check3 = new Checking(0003, 500, "Third Checking Account", 0);
  // Initialize the savings accounts.
  IAccount savings1 = new Savings(0004, 0, "First Savings Account", 4.9);
  IAccount savings2 = new Savings(0005, 100, "Second Savings Account", 8.9);
  IAccount savings3 = new Savings(0006, 0, "Third Savings Account", 1.1);
  // Initialize the savings accounts.
  // 1000 credit line approved, 1000 borrowed already
  IAccount credit1 = new Credit(0004, 1000, "First Credit Account", 1000, 4.9);
  // 200 credit line approved, 100 borrowed already
  IAccount credit2 = new Credit(0005, 100, "Second Credit Account", 200, 8.9);
  // 1000 credit line approved, no money borrowed yet
  IAccount credit3 = new Credit(0006, 0, "Third Credit Account", 1000, 1.1);
  //Initialize the checking accounts.
  IAccount pcheck1 = 
    new PremiumChecking(0001, 0, "First PremiumChecking Account", 0, 0);
  IAccount pcheck2 = 
    new PremiumChecking(0002, 100, "Second Checking Account", 50, 5);
  IAccount pcheck3 = 
    new PremiumChecking(0003, 500, "Third PremiumChecking Account", 0, 25);

  // Tests the exceptions we expect to be thrown when
  // performing an "illegal" action.
  public void testExceptions(Tester t){
    // test that check1.withdraw(100) throws a RuntimeException
    // with the message "Insufficient Funds".
    t.checkExpect(
        // optional description of the test case
        "The test should pass, we supplied the right information",
        // the exception we expect to throw
        new RuntimeException("Insufficient Funds in the checking account."),
        // the object that invokes the method that throws the exception
        check1,
        // the name of the method that should throw exception
        "withdraw",
        // arguments for the method invocation - as many as are needed, or none
        100); 

    // test that savings1.withdraw(100) throws a RuntimeException
    // with the message "Insufficient Funds".
    t.checkExpect(
        "The test should pass, we supplied the right information",
        new RuntimeException("Insufficient Funds in the savings account."),
        savings1,
        "withdraw",
        100);

    // test that credit1.withdraw(100) throws a RuntimeException
    // with the message "Insufficient Funds".
    t.checkExpect(
        "The test should pass, we supplied the right information",
        new RuntimeException("Cannot spend above your credit line First Credit Account."),
        credit1,
        "withdraw",
        100);

    // test the pcheck1.withdraw(100) throws a RuntimeExeption
    // with the message "Insufficient Funds".
    t.checkExpect(
        "Blah",
        new RuntimeException("Insufficient Funds in the checking account."),
        pcheck1,
        "withdraw",
        100) ;

  }

  // Tests the withdraw methods inside certain accounts.
  public void testWithdraw(Tester t){
    t.checkExpect(check2.withdraw(49), 
        new Checking(0002, 51, "Second Checking Account", 50));
    t.checkExpect(savings2.withdraw(100), 
        new Savings(0005, 0, "Second Savings Account", 8.9));
    t.checkExpect(credit2.withdraw(100), 
        new Credit(0005, 200, "Second Credit Account", 200, 8.9));
    t.checkExpect(credit2.withdraw(100), 
        new Credit(0005, 200, "Second Credit Account", 200, 8.9));
    t.checkExpect(credit2.withdraw(100), 
        new Credit(0005, 200, "Second Credit Account", 200, 8.9));
    t.checkExpect(credit2.withdraw(100), 
        new Credit(0005, 200, "Second Credit Account", 200, 8.9));
    t.checkExpect(pcheck1.withdraw(0), 
        new PremiumChecking(0001, 0, "First PremiumChecking Account", 0, 0));
    t.checkExpect(pcheck2.withdraw(50), 
        new PremiumChecking(0002, 50, "Second PremiumChecking Account", 50, 5));
  }

  // Tests the deposit methods inside each type ofAAcount.
  public void testDeposit(Tester t){
    t.checkExpect(check1.deposit(100), 
        new Checking(0001, 100, "First Checking Account", 0));
    t.checkExpect(check2.deposit(500), 
        new Checking(0002, 600, "Second Checking Account", 50));
    t.checkExpect(savings1.deposit(100), 
        new Savings(0004, 100, "First Savings Account", 4.9));
    t.checkExpect(savings2.deposit(100),
        new Savings(0005, 200, "Second Savings Account", 8.9));
    t.checkExpect(credit1.deposit(100),
        new Credit(0004, 900, "First Credit Account", 1000, 4.9));
    t.checkExpect(credit2.deposit(100), 
        new Credit(0005, 0, "Second Credit Account", 200, 8.9));
    t.checkExpect(pcheck1.deposit(100), 
        new PremiumChecking(0001, 100, "First PremiumChecking Account", 0, 5));
    t.checkExpect(pcheck2.deposit(500), 
        new PremiumChecking(0002, 600, "Second PremiumChecking Account", 50, 35));
  }

  // Tests the canWithdraw method inside each type ofAAcount.
  public void testCanWithdraw(Tester t){
    t.checkExpect(check1.canWithdraw(100), 
        false);
    t.checkExpect(check2.canWithdraw(100), 
        true);
    t.checkExpect(savings1.canWithdraw(100), 
        false);
    t.checkExpect(savings2.canWithdraw(100),
        true);
    t.checkExpect(credit1.canWithdraw(100),
        true);
    t.checkExpect(credit2.canWithdraw(100), 
        true);
    t.checkExpect(pcheck1.canWithdraw(0), 
        true);
    t.checkExpect(pcheck2.canWithdraw(600), 
        false);
  }

  // Test toSavings
  public void testExceptionsTo(Tester t){
    // Test toChecking
    t.checkExpect(
        // optional description of the test case
        "The test should pass, we supplied the right information",
        // the exception we expect to throw
        new RuntimeException("This is the wrong type of account"),
        // the object that invokes the method that throws the exception
        savings1,
        // the name of the method that should throw exception
        "toChecking"); 

    // Test toSavings
    t.checkExpect(
        // optional description of the test case
        "The test should pass, we supplied the right information",
        // the exception we expect to throw
        new RuntimeException("This is the wrong type of account"),
        // the object that invokes the method that throws the exception
        credit1,
        // the name of the method that should throw exception
        "toSavings"); 

    // Test toCredit
    t.checkExpect(
        // optional description of the test case
        "The test should pass, we supplied the right information",
        // the exception we expect to throw
        new RuntimeException("This is the wrong type of account"),
        // the object that invokes the method that throws the exception
        check1,
        // the name of the method that should throw exception
        "toCredit");

    // Test toSavings
    t.checkExpect(
        // optional description of the test case
        "The test should pass, we supplied the right information",
        // the exception we expect to throw
        new RuntimeException("This is the wrong type of account"),
        // the object that invokes the method that throws the exception
        savings1,
        // the name of the method that should throw exception
        "toPremiumChecking");
  }

  // Test isChecking
  public void testIsChecking(Tester t){
    t.checkExpect(credit1.isChecking(), 
        false);
    t.checkExpect(check2.isChecking(), 
        true);
    t.checkExpect(pcheck2.isChecking(), 
        false);
  }
  // Test isCredit
  public void testIsCredit(Tester t){
    t.checkExpect(credit1.isCredit(), 
        true);
    t.checkExpect(check2.isCredit(), 
        false);
  }
  // Test isSavings
  public void testIsSavings(Tester t){
    t.checkExpect(check1.isSavings(), 
        false);
    t.checkExpect(savings2.isSavings(), 
        true);
  }
  // Test isPremiumChecking
  public void testIsPremiumChecking(Tester t){
    t.checkExpect(check1.isPremiumChecking(), 
        false);
    t.checkExpect(pcheck2.isPremiumChecking(), 
        true);
  }

  // Test sameChecking
  public void testSameChecking(Tester t){
    t.checkExpect(check1.toChecking().sameChecking(check2.toChecking()), 
        false);
    t.checkExpect(check2.toChecking().sameChecking(check2.toChecking()), 
        true);
  }

  // Test sameCredit
  public void testSameCredit(Tester t){
    t.checkExpect(credit1.toCredit().sameCredit(credit2.toCredit()), 
        false);
    t.checkExpect(credit2.toCredit().sameCredit(credit2.toCredit()), 
        true);
  }

  // Test sameSavings
  public void testSameSavings(Tester t){
    t.checkExpect(savings1.toSavings().same(savings2.toSavings()), 
        false);
    t.checkExpect(savings2.toSavings().same(savings2.toSavings()), 
        true);
  }

  // Test samePremiumChecking
  public void testSamePremiumChecking(Tester t){
    t.checkExpect(pcheck1.toChecking().sameChecking(pcheck2.toChecking()), 
        false);
    t.checkExpect(pcheck2.toChecking().sameChecking(pcheck2.toChecking()), 
        true);
  }

  // Tests the same method inside each type ofAAcount.
  public void testSame(Tester t){
    t.checkExpect(check1.same(check2), 
        false);
    t.checkExpect(check2.same(check2), 
        true);
    t.checkExpect(check2.same(savings2), 
        false);
    // Taken to the bottom.
    t.checkExpect(check2.same(pcheck1), 
        false);
    t.checkExpect(savings1.same(savings2), 
        false);
    t.checkExpect(savings2.same(new Savings(0005, 100, "Second Savings Account", 8.9)),
        true);
    t.checkExpect(savings1.same(check2), 
        false);
    t.checkExpect(credit1.same(credit2),
        false);
    t.checkExpect(credit2.same(new Credit(0005, 100, "Second Credit Account", 200, 8.9)), 
        true);
    t.checkExpect(credit1.same(check2),
        false);
    t.checkExpect(pcheck1.same(pcheck2), 
        false);
    t.checkExpect(pcheck2.same(new PremiumChecking(0002, 100, "Second PremiumChecking Account", 50, 5)), 
        true);
    t.checkExpect(pcheck2.same(check2), 
        false);
    t.checkExpect(pcheck2.same(check1), 
        false);
    // This test is the one where instanceOf causes problems, 
    // because a pcheck is an instance of check.
    // In order to make it work we had to change the names to be the same
    t.checkExpect(check2.same(pcheck2), 
        false);
  }
}
